home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / SWAG / SWAGA_C / ARCHIVES.SWG / 0028_LZSS compression library.pas < prev    next >
Pascal/Delphi Source File  |  1995-02-28  |  39KB  |  1,225 lines

  1.  
  2. Unit LZSSUnit;
  3. {
  4.    LZSSUNIT - Compress and uncompress unit using LZ77 algorithm for
  5.    Borland (Turbo) Pascal version 7.0.
  6.  
  7.    Assembler Programmer: Andy Tam, Pascal Conversion: Douglas Webb,
  8.    Unit Conversion and Dynamic Memory Allocation: Andrew Eigus.
  9.  
  10.    Public Domain version 1.02, last changed on 30.11.94.
  11.    Target platforms: DOS, DPMI, Windows.
  12.  
  13.    Written by Andrew Eigus (aka: Mr. Byte) of:
  14.    Fidonet: 2:5100/33,
  15.    Internet: aeigus@fgate.castle.riga.lv, aeigus@kristin.cclu.lv.
  16. }
  17.  
  18. interface
  19.  
  20. {#Z+}
  21. { This unit is ready for use with Dj. Murdoch's ScanHelp utility which
  22.   will make a Borland .TPH file for it. }
  23. {#Z-}
  24.  
  25. const
  26.   LZRWBufSize     = 8192; { Read buffer size }
  27.  
  28. {#Z+}
  29.   N           = 4096;  { Bigger N -> Better compression on big files only. }
  30.   F           = 18;
  31.   Threshold   = 2;
  32.   Nul         = N * 2;
  33.   InBufPtr    : word = LZRWBufSize;
  34.   InBufSize   : word = LZRWBufSize;
  35.   OutBufPtr   : word = 0;
  36. {#Z-}
  37.  
  38. type
  39. {#X TWriteProc}{#X LZSquash}{#X LZUnsquash}
  40.  
  41.   TReadProc = function(var ReadBuf; var NumRead : word) : word;
  42.   { This is declaration for custom read function. It should read
  43.     #LZRWBufSize# bytes from ReadBuf. The return value is ignored. }
  44.  
  45. {#X TReadProc}{#X LZSquash}{#X LZUnsquash}
  46.   TWriteProc = function(var WriteBuf; Count : word; var NumWritten : word) :
  47. word;  { This is declaration for custom write function. It should write
  48.     Count bytes into WriteBuf and return number of actual bytes written
  49.     into NumWritten variable. The return value is ignored. }
  50.  
  51. {#Z+}
  52.   PLZRWBuffer = ^TLZRWBuffer;
  53.   TLZRWBuffer = array[0..LZRWBufSize - 1] of Byte; { file buffers }
  54.  
  55.   PLZTextBuf = ^TLZTextBuf;
  56.   TLZTextBuf = array[0..N + F - 2] of Byte;
  57.  
  58.   PLeftMomTree = ^TLeftMomTree;
  59.   TLeftMomTree = array[0..N] of Word;
  60.   PRightTree = ^TRightTree;
  61.   TRightTree = array[0..N + 256] of Word;
  62.  
  63. const
  64.   LZSSMemRequired = SizeOf(TLZRWBuffer) * 2 +
  65.     SizeOf(TLZTextBuf) + SizeOf(TLeftMomTree) * 2 + SizeOf(TRightTree);
  66. {#Z-}
  67.  
  68. function LZInit : boolean;
  69. { This function should be called before any other compression routines
  70.   from this unit - it allocates memory and initializes all internal
  71.   variables required by compression procedures. If allocation fails,
  72.   LZInit returns False, this means that there isn't enough memory for
  73.   compression or decompression process. It returns True if initialization
  74.   was successful. }
  75. {#X LZDone}{#X LZSquash}{#X LZUnsquash}
  76.  
  77. procedure LZSquash(ReadProc : TReadProc; WriteProc : TWriteProc);
  78. { This procedure is used for compression. ReadProc specifies custom
  79.   read function that reads data, and WriteProc specifies custom write
  80.   function that writes compressed data. }
  81. {#X LZUnsquash}{#X LZInit}{#X LZDone}
  82.  
  83. procedure LZUnSquash(ReadProc : TReadProc; WriteProc : TWriteProc);
  84. { This procedure is used for decompression. ReadProc specifies custom
  85.   read function that reads compressed data, and WriteProc specifies
  86.   custom write function that writes decompressed data. }
  87. {#X LZSquash}{#X LZInit}{#X LZDone}
  88.  
  89. procedure LZDone;
  90. { This procedure should be called after you finished compression or
  91.   decompression. It deallocates (frees) all memory allocated by LZInit.
  92.   Note: You should always call LZDone after you finished using compression
  93.   routines from this unit. }
  94. {#X LZInit}{#X LZSquash}{#X LZUnsquash}
  95.  
  96. implementation
  97.  
  98. var
  99.   Height, MatchPos, MatchLen, LastLen : word;
  100.   TextBufP : PLZTextBuf;
  101.   LeftP, MomP : PLeftMomTree;
  102.   RightP : PRightTree;
  103.   CodeBuf : array[0..16] of Byte;
  104.   LZReadProc : TReadProc;
  105.   LZWriteProc : TWriteProc;
  106.   InBufP, OutBufP : PLZRWBuffer;
  107.   Bytes : word;
  108.   Initialized : boolean;
  109.  
  110. Function LZSS_Read : word;    { Returns # of bytes read }
  111. Begin
  112.   LZReadProc(InBufP^, Bytes);
  113.   LZSS_Read := Bytes;
  114. End; { LZSS_Read }
  115.  
  116. Function LZSS_Write : word;  { Returns # of bytes written }
  117. Begin
  118.   LZWriteProc(OutBufP^, OutBufPtr, Bytes);
  119.   LZSS_Write := Bytes
  120. End; { LZSS_Write }
  121.  
  122. Procedure Getc; assembler;
  123. Asm
  124. {
  125.   getc : return a character from the buffer
  126.           RETURN : AL = input char
  127.                    Carry set when EOF
  128. }
  129.               push    bx
  130.               mov     bx, inBufPtr
  131.               cmp     bx, inBufSize
  132.               jb      @getc1
  133.               push    cx
  134.               push    dx
  135.               push    di
  136.               push    si
  137.               call    LZSS_Read
  138.               pop     si
  139.               pop     di
  140.               pop     dx
  141.               pop     cx
  142.               mov     inBufSize, ax
  143.               or      ax, ax
  144.               jz      @getc2               { ; EOF }
  145.               xor     bx, bx
  146.   @getc1:
  147.               PUSH    DI
  148.               LES     DI,[InBufP]
  149.               MOV     AL,BYTE PTR [ES:DI+BX]
  150.               POP     DI
  151.               inc     bx
  152.               mov     inBufPtr, bx
  153.               pop     bx
  154.               clc                         { ; clear the carry flag }
  155.               jmp     @end
  156.   @getc2:     pop     bx
  157.               stc                         { ; set carry to indicate EOF }
  158.   @end:
  159. End; { Getc }
  160.  
  161. Procedure Putc; assembler;
  162. {
  163.   putc : put a character into the output buffer
  164.              Entry : AL = output char
  165. }
  166. Asm
  167.               push    bx
  168.               mov     bx, outBufPtr
  169.               PUSH    DI
  170.               LES     DI,[OutBufP]
  171.               MOV     BYTE PTR [ES:DI+BX],AL
  172.               POP     DI
  173.               inc     bx
  174.               cmp     bx, LZRWBufSize
  175.               jb      @putc1
  176.               mov     OutBufPtr,LZRWBufSize   { Just so the flush will work. }
  177.               push    cx
  178.               push    dx
  179.               push    di
  180.               push    si
  181.               call    LZSS_Write
  182.               pop     si
  183.               pop     di
  184.               pop     dx
  185.               pop     cx
  186.               xor     bx, bx
  187.   @putc1:     mov     outBufPtr, bx
  188.               pop     bx
  189. End; { Putc }
  190.  
  191. Procedure InitTree; assembler;
  192. {
  193.   initTree : initialize all binary search trees.  There are 256 BST's, one
  194.              for all strings started with a particular character.  The
  195.              parent is tree K is the node N + K + 1 and it has only a
  196.              right child
  197. }
  198. Asm
  199.       cld
  200.       push    ds
  201.       pop     es
  202.       LES     DI,[RightP]
  203. {      mov     di,offset right}
  204.       add     di, (N + 1) * 2
  205.       mov     cx, 256
  206.       mov     ax, NUL
  207.       rep     stosw
  208.       LES     DI,[MomP]
  209. {      mov     di, offset mom}
  210.       mov     cx, N
  211.       rep     stosw
  212. End; { InitTree }
  213.  
  214. Procedure Splay; assembler;
  215. {
  216.   splay : use splay tree operations to move the node to the 'top' of
  217.            tree.  Note that it will not actual become the root of the tree
  218.            because the root of each tree is a special node.  Instead, it
  219.            will become the right child of this special node.
  220.  
  221.              ENTRY : di = the node to be rotated
  222. }
  223. Asm
  224.   @Splay1:
  225.               PUSH    BX
  226.               LES     BX,[MomP]
  227.               MOV     SI,[ES:BX+DI]
  228.               POP     BX
  229. {              mov     si, [Offset Mom + di]}
  230.               cmp     si, NUL           { ; exit if its parent is a special
  231. node }              ja      @Splay4
  232.               PUSH    DI
  233.               LES     DI,[MomP]
  234.               ADD     DI,SI
  235.               MOV     BX,[ES:DI]
  236. {              mov     bx, [Offset Mom + si]}
  237.               POP     DI
  238.               cmp     bx, NUL           { ; check if its grandparent is special
  239. }              jbe     @Splay5           { ; if not then skip }
  240.               PUSH    BX
  241.               LES     BX,[LeftP]
  242.               CMP     DI,[ES:BX+SI]
  243.               POP     BX
  244. {              cmp     di, [Offset Left + si]} { ; is the current node is a
  245. left child ? }              jne     @Splay2
  246.               PUSH    BX
  247.               LES     BX,[RightP]
  248.               MOV     DX,[ES:BX+DI]
  249. {              mov     dx, [Offset Right + di]}    { ; perform a left zig
  250. operation }              LES     BX,[LeftP]
  251.               MOV     [ES:BX+SI],DX
  252. {              mov     [Offset Left + si], dx}
  253.               LES     BX,[RightP]
  254.               MOV     [ES:BX+DI],SI
  255.               POP     BX
  256. {              mov     [Offset Right + di], si}
  257.               jmp     @Splay3
  258.   @Splay2:
  259.               PUSH    BX
  260.               LES     BX,[LeftP]
  261.               MOV     DX,[ES:BX+DI]
  262. {              mov     dx, [Offset Left + di]}     { ; perform a right zig }
  263.               LES     BX,[RightP]
  264.               MOV     [ES:BX+SI],DX
  265. {              mov     [Offset Right + si], dx}
  266.               LES     BX,[LeftP]
  267.               MOV     [ES:BX+DI],SI
  268.               POP     BX
  269. {              mov     [Offset Left + di], si}
  270.   @Splay3:
  271.               PUSH    SI
  272.               LES     SI,[RightP]
  273.               MOV     [ES:SI+BX],DI
  274.               POP     SI
  275. {              mov     [Offset Right + bx], di}
  276.               xchg    bx, dx
  277.               PUSH    AX
  278.               MOV     AX,BX
  279.               LES     BX,[MomP]
  280.               ADD     BX,AX
  281.               MOV     [ES:BX],SI
  282.               LES     BX,[MomP]
  283.               MOV     [ES:BX+SI],DI
  284.               LES     BX,[MomP]
  285.               MOV     [ES:BX+DI],DX
  286.               MOV     BX,AX
  287.               POP     AX
  288. {              mov     [Offset Mom + bx], si
  289.               mov     [Offset Mom + si], di
  290.               mov     [Offset Mom + di], dx}
  291.   @Splay4:    jmp     @end
  292.   @Splay5:
  293.               PUSH    DI
  294.               LES     DI,[MomP]
  295.               MOV     CX,[ES:DI+BX]
  296.               POP     DI
  297. {              mov     cx, [Offset Mom + bx]}
  298.               PUSH    BX
  299.               LES     BX,[LeftP]
  300.               CMP     DI,[ES:BX+SI]
  301.               POP     BX
  302. {              cmp     di, [Offset Left + si]}
  303.               jne     @Splay7
  304.               PUSH    DI
  305.               LES     DI,[LeftP]
  306.               CMP     SI,[ES:DI+BX]
  307.               POP     DI
  308. {              cmp     si, [Offset Left + bx]}
  309.               jne     @Splay6
  310.               PUSH    AX
  311.               MOV     AX,DI
  312.               LES     DI,[RightP]
  313.               ADD     DI,SI
  314.               MOV     DX,[ES:DI]
  315. {              mov     dx, [Offset Right + si]   } { ; perform a left zig-zig
  316. operation }              LES     DI,[LeftP]
  317.               MOV     [ES:DI+BX],DX
  318. {              mov     [Offset Left + bx], dx}
  319.               xchg    bx, dx
  320.               LES     DI,[MomP]
  321.               MOV     [ES:DI+BX],DX
  322. {              mov     [Offset Mom + bx], dx}
  323.               LES     DI,[RightP]
  324.               ADD     DI,AX
  325.               MOV     BX,[ES:DI]
  326. {              mov     bx, [Offset Right + di]}
  327.               LES     DI,[LeftP]
  328.               ADD     DI,SI
  329.               MOV     [ES:DI],BX
  330.               LES     DI,[MomP]
  331.               MOV     [ES:DI+BX],SI
  332. {              mov     [Offset Left +si], bx
  333.               mov     [Offset Mom + bx], si}
  334.               mov     bx, dx
  335.               LES     DI,[RightP]
  336.               ADD     DI,SI
  337.               MOV     [ES:DI],BX
  338.               LES     DI,[RightP]
  339.               ADD     DI,AX
  340.               MOV     [ES:DI],SI
  341. {              mov     [Offset Right + si], bx
  342.               mov     [Offset Right + di], si}
  343.               LES     DI,[MomP]
  344.               MOV     [ES:DI+BX],SI
  345.               LES     DI,[MomP]
  346.               ADD     DI,SI
  347.               STOSW
  348.               MOV     DI,AX
  349.               POP     AX
  350. {              mov     [Offset Mom + bx], si
  351.               mov     [Offset Mom + si], di}
  352.               jmp     @Splay9
  353.   @Splay6:
  354.               PUSH    AX
  355.               MOV     AX,SI
  356.               LES     SI,[LeftP]
  357.               ADD     SI,DI
  358.               MOV     DX,[ES:SI]
  359. {              mov     dx, [Offset Left + di]}     { ; perform a left zig-zag
  360. operation }              LES     SI,[RightP]
  361.               MOV     [ES:SI+BX],DX
  362. {              mov     [Offset Right + bx], dx}
  363.               xchg    bx, dx
  364.               LES     SI,[MomP]
  365.               MOV     [ES:SI+BX],DX
  366. {              mov     [Offset Mom + bx], dx}
  367.               LES     SI,[RightP]
  368.               ADD     SI,DI
  369.               MOV     BX,[ES:SI]
  370. {              mov     bx, [Offset Right + di]}
  371.               LES     SI,[LeftP]
  372.               ADD     SI,AX
  373.               MOV     [ES:SI],BX
  374. {              mov     [Offset Left + si], bx}
  375.               LES     SI,[MomP]
  376.               MOV     [ES:SI+BX],AX
  377. {              mov     [Offset Mom + bx], si}
  378.               mov     bx, dx
  379.               LES     SI,[LeftP]
  380.               ADD     SI,DI
  381.               MOV     [ES:SI],BX
  382. {              mov     [Offset Left + di], bx}
  383.               LES     SI,[RightP]
  384.               ADD     SI,DI
  385.               MOV     [ES:SI],AX
  386. {              mov     [Offset Right + di], si}
  387.               LES     SI,[MomP]
  388.               ADD     SI,AX
  389.               MOV     [ES:SI],DI
  390. {              mov     [Offset Mom + si], di}
  391.               LES     SI,[MomP]
  392.               MOV     [ES:SI+BX],DI
  393.               MOV     SI,AX
  394.               POP     AX
  395. {              mov     [Offset Mom + bx], di}
  396.               jmp     @Splay9
  397.   @Splay7:
  398.               PUSH    DI
  399.               LES     DI,[RightP]
  400.               CMP     SI,[ES:DI+BX]
  401.               POP     DI
  402. {              cmp     si, [Offset Right + bx]}
  403.               jne     @Splay8
  404.               PUSH    AX
  405.               MOV     AX,SI
  406.               LES     SI,[LeftP]
  407.               ADD     SI,AX
  408.               MOV     DX,[ES:SI]
  409. {              mov     dx, [Offset Left + si]}     { ; perform a right zig-zig
  410. }              LES     SI,[RightP]
  411.               MOV     [ES:SI+BX],DX
  412. {              mov     [Offset Right + bx], dx}
  413.               xchg    bx, dx
  414.               LES     SI,[MomP]
  415.               MOV     [ES:SI+BX],DX
  416. {              mov     [Offset Mom + bx], dx}
  417.               LES     SI,[LeftP]
  418.               ADD     SI,DI
  419.               MOV     BX,[ES:SI]
  420. {              mov     bx, [Offset Left + di]}
  421.               LES     SI,[RightP]
  422.               ADD     SI,AX
  423.               MOV     [ES:SI],BX
  424. {              mov     [Offset Right + si], bx}
  425.               LES     SI,[MomP]
  426.               MOV     [ES:SI+BX],AX
  427. {              mov     [Offset Mom + bx], si}
  428.               mov     bx, dx
  429.               LES     SI,[LeftP]
  430.               ADD     SI,AX
  431.               MOV     [ES:SI],BX
  432. {              mov     [Offset Left + si], bx}
  433.               LES     SI,[LeftP]
  434.               ADD     SI,DI
  435.               MOV     [ES:SI],AX
  436. {              mov     [Offset Left + di], si}
  437.               LES     SI,[MomP]
  438.               MOV     [ES:SI+BX],AX
  439. {              mov     [Offset Mom + bx], si}
  440.               LES     SI,[MomP]
  441.               ADD     SI,AX
  442.               MOV     [ES:SI],DI
  443. {              mov     [Offset Mom + si], di}
  444.               MOV     SI,AX
  445.               POP     AX
  446.               jmp     @Splay9
  447.   @Splay8:
  448.               PUSH    AX
  449.               MOV     AX,SI
  450.               LES     SI,[RightP]
  451.               ADD     SI,DI
  452.               MOV     DX,[ES:SI]
  453. {              mov     dx, [Offset Right + di]}    { ; perform a right zig-zag
  454. }              LES     SI,[LeftP]
  455.               MOV     [ES:SI+BX],DX
  456. {              mov     [Offset Left + bx], dx}
  457.               xchg    bx, dx
  458.               LES     SI,[MomP]
  459.               MOV     [ES:SI+BX],DX
  460. {              mov     [Offset Mom + bx], dx}
  461.               LES     SI,[LeftP]
  462.               ADD     SI,DI
  463.               MOV     BX,[ES:SI]
  464. {              mov     bx, [Offset Left + di]}
  465.               LES     SI,[RightP]
  466.               ADD     SI,AX
  467.               MOV     [ES:SI],BX
  468. {              mov     [Offset Right + si], bx}
  469.               LES     SI,[MomP]
  470.               MOV     [ES:SI+BX],AX
  471. {              mov     [Offset Mom + bx], si}
  472.               mov     bx, dx
  473.               LES     SI,[RightP]
  474.               ADD     SI,DI
  475.               MOV     [ES:SI],BX
  476. {              mov     [Offset Right + di], bx}
  477.               LES     SI,[LeftP]
  478.               ADD     SI,DI
  479.               MOV     [ES:SI],AX
  480. {              mov     [Offset Left + di], si}
  481.               LES     SI,[MomP]
  482.               ADD     SI,AX
  483.               MOV     [ES:SI],DI
  484.               LES     SI,[MomP]
  485.               MOV     [ES:SI+BX],DI
  486. {              mov     [Offset Mom + si], di
  487.               mov     [Offset Mom + bx], di}
  488.               MOV     SI,AX
  489.               POP     AX
  490.   @Splay9:    mov     si, cx
  491.               cmp     si, NUL
  492.               ja      @Splay10
  493.               PUSH    DI
  494.               LES     DI,[LeftP]
  495.               ADD     DI,SI
  496.               CMP     BX,[ES:DI]
  497.               POP     DI
  498. {              cmp     bx, [Offset Left + si]}
  499.               jne     @Splay10
  500.               PUSH    BX
  501.               LES     BX,[LeftP]
  502.               MOV     [ES:BX+SI],DI
  503.               POP     BX
  504. {              mov     [Offset Left + si], di}
  505.               jmp     @Splay11
  506.   @Splay10:
  507.               PUSH    BX
  508.               LES     BX,[RightP]
  509.               MOV     [ES:BX+SI],DI
  510.               POP     BX
  511. {              mov     [Offset Right + si], di}
  512.   @Splay11:
  513.               PUSH    BX
  514.               LES     BX,[MomP]
  515.               MOV     [ES:BX+DI],SI
  516.               POP     BX
  517. {              mov     [Offset Mom + di], si}
  518.               jmp     @Splay1
  519.   @end:
  520. End; { SPlay }
  521.  
  522. Procedure InsertNode; assembler;
  523. {
  524.   insertNode : insert the new node to the corresponding tree.  Note that the
  525.                position of a string in the buffer also served as the node
  526.                number.
  527.              ENTRY : di = position in the buffer
  528. }
  529. Asm
  530.               push    si
  531.               push    dx
  532.               push    cx
  533.               push    bx
  534.               mov     dx, 1
  535.               xor     ax, ax
  536.               mov     matchLen, ax
  537.               mov     height, ax
  538.               LES     SI,[TextBufP]
  539.               ADD     SI,DI
  540.               MOV     AL,BYTE PTR [ES:SI]
  541. {             mov     al, byte ptr [Offset TextBuf + di]}
  542.               shl     di, 1
  543.               add     ax, N + 1
  544.               shl     ax, 1
  545.               mov     si, ax
  546.               mov     ax, NUL
  547.               PUSH    BX
  548.               LES     BX,[RightP]
  549.               MOV     WORD PTR [ES:BX+DI],AX
  550. {              mov     word ptr [Offset Right + di], ax}
  551.               LES     BX,[LeftP]
  552.               MOV     WORD PTR [ES:BX+DI],AX
  553.               POP     BX
  554. {              mov     word ptr [Offset Left + di], ax}
  555.   @Ins1:inc     height
  556.               cmp     dx, 0
  557.               jl      @Ins3
  558.               PUSH    DI
  559.               LES     DI,[RightP]
  560.               ADD     DI,SI
  561.               MOV     AX,WORD PTR [ES:DI]
  562.               POP     DI
  563. {              mov     ax, word ptr [Offset Right + si]}
  564.               cmp     ax, NUL
  565.               je      @Ins2
  566.               mov     si, ax
  567.               jmp     @Ins5
  568.   @Ins2:
  569.               PUSH    BX
  570.               LES     BX,[RightP]
  571.               MOV     WORD PTR [ES:BX+SI],DI
  572. {              mov     word ptr [Offset Right + si], di}
  573.               LES     BX,[MomP]
  574.               MOV     WORD PTR [ES:BX+DI],SI
  575.               POP     BX
  576. {              mov     word ptr [Offset Mom + di], si}
  577.               jmp     @Ins11
  578.   @Ins3:
  579.               PUSH    BX
  580.               LES     BX,[LeftP]
  581.               ADD     BX,SI
  582.               MOV     AX,WORD PTR [ES:BX]
  583.               POP     BX
  584. {              mov     ax, word ptr [Offset Left + si]}
  585.               cmp     ax, NUL
  586.               je      @Ins4
  587.               mov     si, ax
  588.               jmp     @Ins5
  589.   @Ins4:
  590.               PUSH    BX
  591.               LES     BX,[LeftP]
  592.               ADD     BX,SI
  593.               MOV     WORD PTR [ES:BX],DI
  594. {              mov     word ptr [Offset Left + si], di}
  595.               LES     BX,[MomP]
  596.               ADD     BX,DI
  597.               MOV     WORD PTR [ES:BX],SI
  598.               POP     BX
  599. {              mov     word ptr [Offset Mom + di], si}
  600.               jmp     @Ins11
  601.   @Ins5:      mov     bx, 1
  602.               shr     si, 1
  603.               shr     di, 1
  604.               xor     ch, ch
  605.               xor     dh, dh
  606.   @Ins6:
  607.               PUSH    SI
  608.               LES     SI,[TextBufP]
  609.               ADD     SI,DI
  610.               MOV     DL,BYTE PTR [ES:SI+BX]
  611.               POP     SI
  612.               PUSH    DI
  613.               LES     DI,[TextBufP]
  614.               ADD     DI,SI
  615.               MOV     CL,BYTE PTR [ES:DI+BX]
  616.               POP     DI
  617. {              mov     dl, byte ptr [Offset Textbuf + di + bx]
  618.               mov     cl, byte ptr [Offset TextBuf + si + bx]}
  619.               sub     dx, cx
  620.               jnz     @Ins7
  621.               inc     bx
  622.               cmp     bx, F
  623.               jb      @Ins6
  624.   @Ins7:      shl     si, 1
  625.               shl     di, 1
  626.               cmp     bx, matchLen
  627.               jbe     @Ins1
  628.               mov     ax, si
  629.               shr     ax, 1
  630.               mov     matchPos, ax
  631.               mov     matchLen, bx
  632.               cmp     bx, F
  633.               jb      @Ins1
  634.   @Ins8:
  635.               PUSH    CX
  636.               LES     BX,[MomP]
  637.               MOV     AX,WORD PTR [ES:BX+SI]
  638. {              mov     ax, word ptr [Offset Mom + si]}
  639.               LES     BX,[MomP]
  640.               MOV     WORD PTR [ES:BX+DI],AX
  641. {              mov     word ptr [Offset Mom + di], ax}
  642.               LES     BX,[LeftP]
  643.               MOV     CX,WORD PTR [ES:BX+SI]
  644. {              mov     bx, word ptr [Offset Left + si]}
  645.               LES     BX,[LeftP]
  646.               MOV     WORD PTR [ES:BX+DI],CX
  647. {              mov     word ptr [Offset Left + di], bx}
  648.               LES     BX,[MomP]
  649.               ADD     BX,CX
  650.               MOV     WORD PTR [ES:BX],DI
  651. {              mov     word ptr [Offset Mom + bx], di}
  652.               LES     BX,[RightP]
  653.               MOV     CX,WORD PTR [ES:BX+SI]
  654. {              mov     bx, word ptr [Offset Right + si]}
  655.               LES     BX,[RightP]
  656.               MOV     WORD PTR [ES:BX+DI],CX
  657. {              mov     word ptr [Offset Right + di], bx}
  658.               LES     BX,[MomP]
  659.               ADD     BX,CX
  660.               MOV     WORD PTR [ES:BX],DI
  661. {              mov     word ptr [Offset Mom + bx], di}
  662.               LES     BX,[MomP]
  663.               MOV     CX,WORD PTR [ES:BX+SI]
  664. {              mov     bx, word ptr [Offset Mom + si]}
  665.               MOV     BX,CX
  666.               POP     CX
  667.               PUSH    DI
  668.               LES     DI,[RightP]
  669.               CMP     SI,WORD PTR [ES:DI+BX]
  670.               POP     DI
  671. {              cmp     si, word ptr [Offset Right + bx]}
  672.               jne     @Ins9
  673.               PUSH    SI
  674.               LES     SI,[RightP]
  675.               MOV     WORD PTR [ES:SI+BX],DI
  676.               POP     SI
  677. {              mov     word ptr [Offset Right + bx], di}
  678.               jmp     @Ins10
  679.   @Ins9:
  680.               PUSH    SI
  681.               LES     SI,[LeftP]
  682.               MOV     WORD PTR [ES:SI+BX],DI
  683.               POP     SI
  684. {              mov     word ptr [Offset Left + bx], di}
  685.   @Ins10:
  686.               PUSH    DI
  687.               LES     DI,[MomP]
  688.               ADD     DI,SI
  689.               MOV     WORD PTR [ES:DI],NUL
  690.               POP     DI
  691. {              mov     word ptr [Offset Mom + si], NUL}
  692.   @Ins11:     cmp     height, 30
  693.               jb      @Ins12
  694.               call    Splay
  695.   @Ins12:     pop     bx
  696.               pop     cx
  697.               pop     dx
  698.               pop     si
  699.               shr     di, 1
  700. End; { InsertNode }
  701.  
  702.  
  703. Procedure DeleteNode; assembler;
  704. {
  705.    deleteNode : delete the node from the tree
  706.  
  707.             ENTRY : SI = position in the buffer
  708. }
  709. Asm
  710.               push    di
  711.               push    bx
  712.               shl     si, 1
  713.               PUSH    DI
  714.               LES     DI,[MomP]
  715.               ADD     DI,SI
  716.               CMP     WORD PTR [ES:DI],NUL
  717.               POP     DI
  718. {              cmp     word ptr [Offset Mom + si], NUL}   { ; if it has no
  719. parent then exit }              je      @del7
  720.               PUSH    DI
  721.               LES     DI,[RightP]
  722.               ADD     DI,SI
  723.               CMP     WORD PTR [ES:DI],NUL
  724.               POP     DI
  725. {              cmp     word ptr [Offset Right + si], NUL} { ; does it have
  726. right child ? }              je      @del8
  727.               PUSH    BX
  728.               LES     BX,[LeftP]
  729.               MOV     DI,WORD PTR [ES:BX+SI]
  730.               POP     BX
  731. {              mov     di, word ptr [Offset Left + si] }  { ; does it have left
  732. child ? }              cmp     di, NUL
  733.               je      @del9
  734.               PUSH    SI
  735.               LES     SI,[RightP]
  736.               ADD     SI,DI
  737.               MOV     AX,WORD PTR [ES:SI]
  738.               POP     SI
  739. {              mov     ax, word ptr [Offset Right + di]}  { ; does it have
  740. right grandchild ? }              cmp     ax, NUL
  741.               je      @del2                             { ; if no then skip }
  742.   @del1:      mov     di, ax                            { ; find the rightmost
  743. node in }              PUSH    SI
  744.               LES     SI,[RightP]
  745.               ADD     SI,DI
  746.               MOV     AX,WORD PTR [ES:SI]
  747.               POP     SI
  748. {              mov     ax, word ptr [Offset Right + di] } { ;   the right
  749. subtree }              cmp     ax, NUL
  750.               jne     @del1
  751.               PUSH    CX
  752.               MOV     CX,SI
  753.               LES     SI,[MomP]
  754.               ADD     SI,DI
  755.               MOV     BX,WORD PTR [ES:SI]
  756. {              mov     bx, word ptr [Offset Mom + di] }   { ; move this node as
  757. the root of }              LES     SI,[LeftP]
  758.               ADD     SI,DI
  759.               MOV     AX,WORD PTR [ES:SI]
  760. {              mov     ax, word ptr [Offset Left + di]}   { ;   the subtree }
  761.               LES     SI,[RightP]
  762.               MOV     WORD PTR [ES:SI+BX],AX
  763. {              mov     word ptr [Offset Right + bx], ax}
  764.               xchg    ax, bx
  765.               LES     SI,[MomP]
  766.               MOV     WORD PTR [ES:SI+BX],AX
  767. {              mov     word ptr [Offset Mom + bx], ax}
  768.               LES     SI,[LeftP]
  769.               ADD     SI,CX
  770.               MOV     BX,WORD PTR [ES:SI]
  771. {              mov     bx, word ptr [Offset Left + si]}
  772.               LES     SI,[LeftP]
  773.               ADD     SI,DI
  774.               MOV     WORD PTR [ES:SI],BX
  775. {              mov     word ptr [Offset Left + di], bx}
  776.               LES     SI,[MomP]
  777.               MOV     WORD PTR [ES:SI+BX],DI
  778. {              mov     word ptr [Offset Mom + bx], di}
  779.               MOV     SI,CX
  780.               POP     CX
  781.   @del2:
  782.               PUSH    CX
  783.               MOV     CX,SI
  784.               LES     SI,[RightP]
  785.               ADD     SI,CX
  786.               MOV     BX,WORD PTR [ES:SI]
  787. {              mov     bx, word ptr [Offset Right + si]}
  788.               LES     SI,[RightP]
  789.               ADD     SI,DI
  790.               MOV     WORD PTR [ES:SI],BX
  791. {              mov     word ptr [Offset Right + di], bx}
  792.               LES     SI,[MomP]
  793.               MOV     WORD PTR [ES:SI+BX],DI
  794.               MOV     SI,CX
  795.               POP     CX
  796. {              mov     word ptr [Offset Mom + bx], di}
  797.   @del3:
  798.               PUSH    CX
  799.               MOV     CX,DI
  800.               LES     DI,[MomP]
  801.               ADD     DI,SI
  802.               MOV     BX,WORD PTR [ES:DI]
  803. {              mov     bx, word ptr [Offset Mom + si]}
  804.               LES     DI,[MomP]
  805.               ADD     DI,CX
  806.               MOV     WORD PTR [ES:DI],BX
  807. {              mov     word ptr [Offset Mom + di], bx}
  808.               MOV     DI,CX
  809.               POP     CX
  810.               PUSH    DI
  811.               LES     DI,[RightP]
  812.               CMP     SI,WORD PTR [ES:DI+BX]
  813.               POP     DI
  814. {              cmp     si, word ptr [Offset Right + bx]}
  815.               jne     @del4
  816.               PUSH    SI
  817.               LES     SI,[RightP]
  818.               MOV     WORD PTR [ES:SI+BX],DI
  819.               POP     SI
  820. {              mov     word ptr [Offset Right + bx], di}
  821.               jmp     @del5
  822.   @del4:
  823.               PUSH    SI
  824.               LES     SI,[LeftP]
  825.               MOV     WORD PTR [ES:SI+BX],DI
  826.               POP     SI
  827. {              mov     word ptr [Offset Left + bx], di}
  828.   @del5:
  829.               PUSH    DI
  830.               LES     DI,[MomP]
  831.               ADD     DI,SI
  832.               MOV     WORD PTR [ES:DI],NUL
  833.               POP     DI
  834. {              mov     word ptr [Offset Mom + si], NUL}
  835.   @del7:      pop     bx
  836.               pop     di
  837.               shr     si, 1
  838.               jmp     @end;
  839.   @del8:
  840.               PUSH    BX
  841.               LES     BX,[LeftP]
  842.               MOV     DI,WORD PTR [ES:BX+SI]
  843.               POP     BX
  844. {              mov     di, word ptr [Offset Left + si]}
  845.               jmp     @del3
  846.   @del9:
  847.               PUSH    BX
  848.               LES     BX,[RightP]
  849.               MOV     DI,WORD PTR [ES:BX+SI]
  850.               POP     BX
  851. {              mov     di, word ptr [Offset Right + si]}
  852.               jmp     @del3
  853.   @end:
  854. End; { DeleteNode }
  855.  
  856. Procedure Encode; assembler;
  857. Asm
  858.               call    initTree
  859.               xor     bx, bx
  860.               mov     [Offset CodeBuf + bx], bl
  861.               mov     dx, 1
  862.               mov     ch, dl
  863.               xor     si, si
  864.               mov     di, N - F
  865.   @Encode2:   call    getc
  866.               jc      @Encode3
  867.               PUSH    SI
  868.               LES     SI,[TextBufP]
  869.               ADD     SI,DI
  870.               MOV     BYTE PTR [ES:SI+BX],AL
  871.               POP     SI
  872. {              mov     byte ptr [Offset TextBuf +di + bx], al}
  873.               inc     bx
  874.               cmp     bx, F
  875.               jb      @Encode2
  876.   @Encode3:   or      bx, bx
  877.               jne     @Encode4
  878.               jmp     @Encode19
  879.   @Encode4:   mov     cl, bl
  880.               mov     bx, 1
  881.               push    di
  882.               sub     di, 1
  883.   @Encode5:   call    InsertNode
  884.               inc     bx
  885.               dec     di
  886.               cmp     bx, F
  887.               jbe     @Encode5
  888.               pop     di
  889.               call    InsertNode
  890.   @Encode6:   mov     ax, matchLen
  891.               cmp     al, cl
  892.               jbe     @Encode7
  893.               mov     al, cl
  894.               mov     matchLen, ax
  895.   @Encode7:   cmp     al, THRESHOLD
  896.               ja      @Encode8
  897.               mov     matchLen, 1
  898.               or      byte ptr codeBuf, ch
  899.               mov     bx, dx
  900.               PUSH    SI
  901.               LES     SI,[TextBufP]
  902.               ADD     SI,DI
  903.               MOV     AL,BYTE PTR [ES:SI]
  904.               POP     SI
  905. {              mov     al, byte ptr [Offset TextBuf + di]}
  906.               mov     byte ptr [Offset CodeBuf + bx], al
  907.               inc     dx
  908.               jmp     @Encode9
  909.   @Encode8:   mov     bx, dx
  910.               mov     al, byte ptr matchPos
  911.               mov     byte ptr [Offset Codebuf + bx], al
  912.               inc     bx
  913.               mov     al, byte ptr (matchPos + 1)
  914.               push    cx
  915.               mov     cl, 4
  916.               shl     al, cl
  917.               pop     cx
  918.               mov     ah, byte ptr matchLen
  919.               sub     ah, THRESHOLD + 1
  920.               add     al, ah
  921.               mov     byte ptr [Offset Codebuf + bx], al
  922.               inc     bx
  923.               mov     dx, bx
  924.   @Encode9:   shl     ch, 1
  925.               jnz     @Encode11
  926.               xor     bx, bx
  927.   @Encode10:  mov     al, byte ptr [Offset CodeBuf + bx]
  928.               call    putc
  929.               inc     bx
  930.               cmp     bx, dx
  931.               jb      @Encode10
  932.               mov     dx, 1
  933.               mov     ch, dl
  934.               mov     byte ptr codeBuf, dh
  935.   @Encode11:  mov     bx, matchLen
  936.               mov     lastLen, bx
  937.               xor     bx, bx
  938.   @Encode12:  call    getc
  939. {              jc      @Encode14}
  940.               jc      @Encode15
  941.               push    ax
  942.               call    deleteNode
  943.               pop     ax
  944.               PUSH    DI
  945.               LES     DI,[TextBufP]
  946.               ADD     DI,SI
  947.               stosb
  948.               POP     DI
  949. {              mov     byte ptr [Offset TextBuf + si], al}
  950.               cmp     si, F - 1
  951.               jae     @Encode13
  952.               PUSH    DI
  953.               LES     DI,[TextBufP]
  954.               ADD     DI,SI
  955.               MOV     BYTE PTR [ES:DI+N],AL
  956.               POP     DI
  957. {              mov     byte ptr [Offset TextBuf + si + N], al}
  958.   @Encode13:  inc     si
  959.               and     si, N - 1
  960.               inc     di
  961.               and     di, N - 1
  962.               call    insertNode
  963.               inc     bx
  964.               cmp     bx, lastLen
  965.               jb      @Encode12
  966. (*  @Encode14:  sub     printCount, bx
  967.               jnc     @Encode15
  968.               mov     ax, printPeriod
  969.               mov     printCount, ax
  970.               push    dx                 { Print out a period as a sign. }
  971.               mov     dl, DBLARROW
  972.               mov     ah, 2
  973.               int     21h
  974.               pop     dx *)
  975.   @Encode15:  cmp     bx, lastLen
  976.               jae     @Encode16
  977.               inc     bx
  978.               call    deleteNode
  979.               inc     si
  980.               and     si, N - 1
  981.               inc     di
  982.               and     di, N - 1
  983.               dec     cl
  984.               jz      @Encode15
  985.               call    insertNode
  986.               jmp     @Encode15
  987.   @Encode16:  cmp     cl, 0
  988.               jbe     @Encode17
  989.               jmp     @Encode6
  990.   @Encode17:  cmp     dx, 1
  991.               jb      @Encode19
  992.               xor     bx, bx
  993.   @Encode18:  mov     al, byte ptr [Offset Codebuf + bx]
  994.               call    putc
  995.               inc     bx
  996.               cmp     bx, dx
  997.               jb      @Encode18
  998.   @Encode19:
  999. End; { Encode }
  1000.  
  1001. Procedure Decode; assembler;
  1002. Asm
  1003.               xor     dx, dx
  1004.               mov     di, N - F
  1005.   @Decode2:   shr     dx, 1
  1006.               or      dh, dh
  1007.               jnz     @Decode3
  1008.               call    getc
  1009.               jc      @Decode9
  1010.               mov     dh, 0ffh
  1011.               mov     dl, al
  1012.   @Decode3:   test    dx, 1
  1013.               jz      @Decode4
  1014.               call    getc
  1015.               jc      @Decode9
  1016.               PUSH    SI
  1017.               LES     SI,[TextBufP]
  1018.               ADD     SI,DI
  1019.               MOV     BYTE PTR [ES:SI],AL
  1020.               POP     SI
  1021. {              mov     byte ptr [Offset TextBuf + di], al}
  1022.               inc     di
  1023.               and     di, N - 1
  1024.               call    putc
  1025.               jmp     @Decode2
  1026.   @Decode4:   call    getc
  1027.               jc      @Decode9
  1028.               mov     ch, al
  1029.               call    getc
  1030.               jc      @Decode9
  1031.               mov     bh, al
  1032.               mov     cl, 4
  1033.               shr     bh, cl
  1034.               mov     bl, ch
  1035.               mov     cl, al
  1036.               and     cl, 0fh
  1037.               add     cl, THRESHOLD
  1038.               inc     cl
  1039.   @Decode5:   and     bx, N - 1
  1040.               PUSH    SI
  1041.               LES     SI,[TextBufP]
  1042.               MOV     AL,BYTE PTR [ES:SI+BX]
  1043.               ADD     SI,DI
  1044.               MOV     BYTE PTR [ES:SI],AL
  1045.               POP     SI
  1046. {              mov     al, byte ptr [Offset TextBuf + bx]
  1047.               mov     byte ptr [Offset TextBuf + di], al}
  1048.               inc     di
  1049.               and     di, N - 1
  1050.               call    putc
  1051.               inc     bx
  1052.               dec     cl
  1053.               jnz     @Decode5
  1054.               jmp     @Decode2
  1055.   @Decode9:
  1056. End; { Decode }
  1057.  
  1058. Function LZInit : boolean;
  1059. Begin
  1060.   if Initialized then Exit;
  1061.   LZInit := False;
  1062.   New(InBufP);
  1063.   New(OutBufP);
  1064.   New(TextBufP);
  1065.   New(LeftP);
  1066.   New(MomP);
  1067.   New(RightP);
  1068.   Initialized := (InBufP <> nil) and (OutBufP <> nil) and
  1069.     (TextBufP <> nil) and (LeftP <> nil) and (MomP <> nil) and (RightP <> nil);
  1070.   if Initialized then LZInit := True else
  1071.   begin
  1072.     Initialized := True;
  1073.     LZDone
  1074.   end
  1075. End; { LZInit }
  1076.  
  1077. Procedure LZDone;
  1078. Begin
  1079.   if Initialized then
  1080.   begin
  1081.     Dispose(InBufP);
  1082.     Dispose(OutBufP);
  1083.     Dispose(RightP);
  1084.     Dispose(MomP);
  1085.     Dispose(LeftP);
  1086.     Dispose(TextBufP);
  1087.     Initialized := False
  1088.   end
  1089. End; { LZDone }
  1090.  
  1091. Procedure LZSquash;
  1092. Begin
  1093.   if Initialized then
  1094.   begin
  1095.     InBufPtr := LZRWBufSize;
  1096.     InBufSize := LZRWBufSize;
  1097.     OutBufPtr := 0;
  1098.     Height := 0;
  1099.     MatchPos := 0;
  1100.     MatchLen := 0;
  1101.     LastLen := 0;
  1102.  
  1103.     FillChar(TextBufP^, SizeOf(TLZTextBuf), 0);
  1104.     FillChar(LeftP^, SizeOf(TLeftMomTree), 0);
  1105.     FillChar(MomP^, SizeOf(TLeftMomTree), 0);
  1106.     FillChar(RightP^, SizeOf(TRightTree), 0);
  1107.     FillChar(CodeBuf, SizeOf(CodeBuf), 0);
  1108.  
  1109.     LZReadProc := ReadProc;
  1110.     LZWriteProc := WriteProc;
  1111.  
  1112.     Encode;
  1113.     LZSS_Write
  1114.   end
  1115. End; { LZSquash }
  1116.  
  1117. Procedure LZUnSquash;
  1118. Begin
  1119.   if Initialized then
  1120.   begin
  1121.     InBufPtr := LZRWBufSize;
  1122.     InBufSize := LZRWBufSize;
  1123.     OutBufPtr := 0;
  1124.     FillChar(TextBufP^, SizeOf(TLZTextBuf), 0);
  1125.  
  1126.     LZReadProc := ReadProc;
  1127.     LZWriteProc := WriteProc;
  1128.  
  1129.     Decode;
  1130.     LZSS_Write
  1131.   end
  1132. End; { LZUnSquash }
  1133.  
  1134. {$IFDEF Windows}
  1135. Function HeapFunc(Size : word) : integer; far; assembler;
  1136. Asm
  1137.   MOV AX,1
  1138. End; { HeapFunc }
  1139. {$ENDIF}
  1140.  
  1141. Begin
  1142. {$IFDEF Windows}
  1143.   HeapError := @HeapFunc;
  1144. {$ENDIF}
  1145.   Initialized := False
  1146. End. { LZSSUNIT }
  1147.  
  1148. { -------------------------  DEMO   ---------------------------------}
  1149.  
  1150. Program LZSSDemo;
  1151. { Copyright (c) 1994 by Andrew Eigus   Fidonet: 2:5100/33 }
  1152. { Demonstrates the use of LZSSUnit (LZSSUNIT.PAS), Public Domain }
  1153.  
  1154. uses LZSSUnit;
  1155.  
  1156. var InFile, OutFile : file;
  1157.  
  1158. Function ToUpper(S : string) : string; assembler;
  1159. Asm
  1160.   PUSH DS
  1161.   CLD
  1162.   LDS SI,S
  1163.   LES DI,@Result
  1164.   LODSB
  1165.   STOSB
  1166.   XOR AH,AH
  1167.   XCHG AX,CX
  1168.   JCXZ @@3
  1169. @@1:
  1170.   LODSB
  1171.   CMP AL,'a'
  1172.   JB  @@2
  1173.   CMP AL,'z'
  1174.   JA  @@2
  1175.   SUB AL,20h
  1176. @@2:
  1177.   STOSB
  1178.   LOOP @@1
  1179. @@3:
  1180.   POP DS
  1181. End; { ToUpper }
  1182.  
  1183. Function ReadProc(var ReadBuf; var NumRead : word) : word; far;
  1184. Begin
  1185.   BlockRead(InFile, ReadBuf, LZRWBufSize, NumRead);
  1186.   Write(#13, FilePos(InFile), ' -> ')
  1187. End; { ReadProc }
  1188.  
  1189. Function WriteProc(var WriteBuf; Count : word; var NumWritten : word) : word;
  1190. far;Begin
  1191.   BlockWrite(OutFile, WriteBuf, Count, NumWritten);
  1192.   Write(FilePos(OutFile), #13)
  1193. End; { WriteProc }
  1194.  
  1195. Begin
  1196.   if ParamCount < 2 then
  1197.   begin
  1198.     WriteLn('Usage: LZSSDEMO <inputfile> <outputfile> [unsquash]');
  1199.     Halt(1)
  1200.   end;
  1201.   if not LZInit then
  1202.   begin
  1203.     WriteLn('Not enough memory');
  1204.     Halt(8)
  1205.   end;
  1206.   Assign(InFile, ParamStr(1));
  1207.   Reset(InFile, 1);
  1208.   if IOResult = 0 then
  1209.   begin
  1210.     Assign(OutFile, ParamStr(2));
  1211.     Rewrite(OutFile, 1);
  1212.     if IOResult = 0 then
  1213.     begin
  1214.       if ToUpper(ParamStr(3)) =  'UNSQUASH' then
  1215.         LZUnSquash(ReadProc, WriteProc)
  1216.       else
  1217.         LZSquash(ReadProc, WriteProc);
  1218.       Close(OutFile)
  1219.     end else WriteLn('Cannot create output file');
  1220.     Close(InFile)
  1221.   end else WriteLn('Cannot open input file');
  1222.   LZDone;
  1223.   WriteLn
  1224. End.
  1225.